/**
 * @file rf_spi.h
 * @brief Header file declaring various SPI functions for use with the RF24 LIbrary
 * @author Jeff Eaton
 */

#include <xc.h>
#include <stdint.h>
#include <stdbool.h>

#ifndef SPI_H
#define	SPI_H

#ifdef	__cplusplus
extern "C" {
#endif

// this isn't necessary at all for the RF library but maybe I'll expand
// on this some day.
typedef enum {SPI_8BIT = 0, SPI_16BIT = 1} SPI_MODE;

/**
 * Initialize SPI stuff
 *
 * @param mode `SPI_8BIT` for byte transfers, `SPI_16BIT` for word transfers
 * @param SS_REG pointer to the LAT register that drives the slave select pin
 * @param SS_pin which bit in that register drives the slave select pin
 */
void spi_init(const SPI_MODE mode, volatile uint16_t* SS_REG, const uint8_t SS_pin);


/**
 * Write a single byte.  The slave select pin will first be driven low,
 * followed by the clock and data pulses, followed by the slave select
 * pin returning high.  Data transfered back from the device (MISO pin)
 * will be returned.
 *
 * @param byte Byte to send TO device (mcu->peripheral)
 * @return Byte sent BY device (peripheral->mcu)
 */
uint8_t spi_write8(const uint8_t byte);


/**
 * Write a single 16 bit word.  The slave select pin will first be driven low,
 * followed by the clock and data pulses, followed by the slave select
 * pin returning high.  Data transfered back from the device (MISO pin)
 * will be returned.
 *
 * @param word Word to send to device (mcu->peripheral)
 * @return Word sent by device (peripheral->mcu)
 */
uint16_t spi_write16(const uint16_t word);



// command byte included specifically for ease of use with the RF library
// ideally these would be generic but I'm probably the only one that's
// going to use this so it isn't a big deal
// use these when you have one command byte and >=2 data bytes

/**
 * Write a command byte @p command, followed by @p len bytes of data stored
 * in @p buf.
 *
 * @param command Byte to write first
 * @param buf Data to send after the command byte
 * @param len Number of bytes to send (not including command byte)
 * @return Byte received when the command byte is written
 */
uint8_t spi_write(const uint8_t command, const uint8_t* buf, const uint8_t len);


/**
 * Write null characters over SPI to read multi-byte data sent from a
 * peripheral.  A command byte will be sent first, followed by @p len iterations
 * of @p nopChar.  Received data will be stored at @p buf.
 *
 * @param command Command byte to send prior to receiving data
 * @param nopChar Null character to write in order to receive data back
 * @param buf Where to store the received data.
 * @param len Number of bytes to read
 * @return Byte received when the command byte is written
 */
uint8_t spi_read(const uint8_t command, const uint8_t nopChar, uint8_t* buf, uint8_t len);


/**
 * Same as spi_write8, but doesn't do anything with the slave select pin.
 *
 * @see spi_write8
 *
 * @param byte Byte to send
 * @return Byte received when @p byte is sent
 */
uint8_t spi_write8_no_ss(const uint8_t byte);


/**
 * Same as spi_write, but doesn't do anything with the slave select pin.
 * There also isn't a command byte, because you could just call 
 * spi_write8_no_ss prior to this and after driving slave select low.
 *
 * @see spi_write
 *
 * @param buf Data to write
 * @param len Number of bytes to write
 * @return the byte received when the last data byte is sent
 */
uint8_t spi_write_no_ss(const uint8_t* buf, uint8_t len);


/**
 * Same as spi_read, but doesn't do anything with the slave select pin.
 *
 * @see spi_read
 *
 * @param command Command byte to transfer
 * @param nopChar Null byte to send in order to receive
 * @param buf Where to store the received data
 * @param len Number of bytes to read
 * @return Byte received when the command byte was written
 */
uint8_t spi_read_no_ss(const uint8_t command, const uint8_t nopChar, uint8_t* buf, uint8_t len);


/**
 * Manually drive the slave select pin high or low.
 *
 * @param state True to drive slave select high, false to drive slave select low.
 */
void spi_ss(const bool state);

#ifdef	__cplusplus
}
#endif

#endif	/* SPI_H */

